﻿using System;
using System.IO;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
//using System.Windows.Media.Animation;
using System.Windows.Controls.Primitives;
using System.Windows.Navigation;

using Heaven.Graphics;
using Heaven.Geometry.Procedural;
using Heaven.SlimDX.Graphics;
using Heaven.Geometry;
using Heaven.Mathematics;
using Heaven.Engine.Animation;


using Heaven.Engine;
using Color = Heaven.Graphics.Color;
using CameraBrowser = Heaven.Engine.CameraBrowser;
using Wavefront = Heaven.Geometry.Importers.Wavefront;
using Visual = Heaven.Engine.Visual;
using Heaven.Engine.Transformations;
using HeavenAnimation = Heaven.Engine.Animation;

namespace Heaven.Showcase.Demos
{
    /// <summary>
    /// Demonstrations. Construction demo
    /// </summary>
	public partial class Prototype
    {
        #region Fields

        // Heaven device compatible with 
        // Windows Presentation Foundation
        WindowsPresentationDevice device = null;
        Renderer render = null;

        // Scene, as a container for objects
        NodeGroup nodeGroup = new NodeGroup();

        // Camera with particular behaviour
        CameraBrowser camera = new CameraBrowser();
        // It's for dragging
        double mouseX = Double.NaN;
        double mouseY = Double.NaN;

        // Flag means that redraw needed
        //bool invalidated = true;
        // Timer to perform rendering when invalidated is set
        DispatcherTimer timer = new DispatcherTimer(DispatcherPriority.Normal);

        // Storyboard for animation timelines
        Storyboard storyboard = new Storyboard();

        #endregion

        #region Initializations

        /// <summary>
        /// Constructor
        /// </summary>
        public Prototype()
		{
			this.InitializeComponent();
            this.Loaded += new RoutedEventHandler(OnLoaded);
            this.Unloaded += new RoutedEventHandler(OnUnloaded);

            /*DoubleAnimationUsingKeyFrames timeline = new DoubleAnimationUsingKeyFrames();
            timeline.KeyFrames.Add(new DoubleKeyFrame());
            

            Storyboard storyboard = new Storyboard();
            storyboard.Children.Add(timeline);
            */

            //renderGroup.Camera = camera;
            
        }

        #endregion

        #region Manipulation routines

        void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                Point point = e.GetPosition(this);

                if (!Double.IsNaN(mouseX))
                {
                    camera.HorisontalRotation += (float)((point.X - mouseX) / 100);
                    camera.VerticalRotation += (float)((point.Y - mouseY) / 100);
                    Invalidate();
                }                
                
                mouseX = point.X;
                mouseY = point.Y;
            }
            else
            {
                mouseX = Double.NaN;
                mouseY = Double.NaN;
            }
        }

        void OnSizeChanged(object sender, SizeChangedEventArgs e)
        {
            camera.Aspect = (float)(e.NewSize.Width / e.NewSize.Height);
            Invalidate();
        }

        void OnTimerTick(object sender, EventArgs e)
        {
            //render.Invalidate();
            /*//if (invalidated)
            {
                invalidated = false;
                Render();                
            }*/
        }

        void OnUnloaded(object sender, RoutedEventArgs e)
        {
            timer.Stop();
        }

        void OnLoaded(object sender, RoutedEventArgs e)
        {
            targetImage.SizeChanged += new SizeChangedEventHandler(OnSizeChanged);
            targetImage.MouseMove += new MouseEventHandler(OnMouseMove);

            // Initialize the timer
            timer.Interval = TimeSpan.FromMilliseconds(1);
            timer.Tick += new EventHandler(OnTimerTick);
            timer.Start();
            //CompositionTarget.Rendering += new EventHandler(OnTimerTick);

            // Initialization of graphics device
            device = new WindowsPresentationDevice(targetImage, Render);
            device.DefaultColor = new Color(0, 0, 0, 0);

            //device.AutoResize = false;
            //device.RenderStates.Wireframe = true;
            //device.RenderStates.CullMode = Heaven.Graphics.CullMode.None;

            // Tuning the scene
            camera.HorisontalRotation = 0.84f;
            camera.VerticalRotation = 1.07f;
            camera.Target = Vector3.Zero;
            camera.Distance = 70;

            LoadVisuals();

            // Start the animations
            storyboard.Clock.Start();
            //timer.Start();

            render = new Renderer(nodeGroup, camera);
            render.Start(device);
            //render.RenderRequest += OnTimerTick;
        }

        #endregion

        #region Loading geometries

        void LoadVisuals()
        {
            AxisAlignedBox aabb = new AxisAlignedBox();

            // Generate a ring's mesh
            Cylinder cylinder = new Cylinder(Vector3.Zero, 6, 0.4);
            cylinder.HasBottomCap = cylinder.HasTopCap = false;
            Polygonal mesh = cylinder.Generate();
            aabb = mesh.AxisAlignedBoundingBox;

            // Create animation timeline for rotation
            Property<Double> angleProperty = new Property<Double>(0);
            RotationTransformation commonRotation = new RotationTransformation(Vector3.ZAxis, new Vector3(0, 0.2, 0), 0);
            commonRotation.Angle = angleProperty;
            Timeline timeline = new HeavenAnimation.Timeline(commonRotation.Angle);
            timeline.Keyframes.Add((Double)0.0, 0.0);
            timeline.Keyframes.Add((Double)Math.PI * 30.0, 120000);
            storyboard.Add(timeline);

            Property<Double> scaleProperty = new Property<Double>(0);
            ScaleTransformation commonScale = new ScaleTransformation(new Vector3(1, 1, 1));
            timeline = new HeavenAnimation.Timeline(commonScale.Scale);
            timeline.Keyframes.Add(new Vector3(1, 1, 1), 0.0);
            timeline.Keyframes.Add(new Vector3(1, 2, 1), 2500);
            timeline.Keyframes.Add(new Vector3(2, 1, 1), 5000);
            timeline.Keyframes.Add(new Vector3(1, 1, 2), 7500);
            timeline.Keyframes.Add(new Vector3(1, 1, 1), 10000);
            timeline.Keyframes.Add(new Vector3(1, 2, 1), 12500);
            timeline.Keyframes.Add(new Vector3(2, 1, 1), 15000);
            timeline.Keyframes.Add(new Vector3(1, 1, 2), 17500);
            timeline.Keyframes.Add(new Vector3(1, 1, 1), 20000);
            storyboard.Add(timeline);

            Property<Vector4> colorProperty = new Property<Vector4>(Vector4.Zero);
            timeline = new Timeline(colorProperty);
            timeline.Keyframes.Add(new Vector4(0, 0, 1, 1), 0.0);
            timeline.Keyframes.Add(new Vector4(0, 1, 0, 1), 5000);
            timeline.Keyframes.Add(new Vector4(1, 0, 0, 1), 10000);
            timeline.Keyframes.Add(new Vector4(1, 1, 0, 1), 15000);
            timeline.Keyframes.Add(new Vector4(0, 1, 1, 1), 20000);
            timeline.Keyframes.Add(new Vector4(1, 0, 1, 1), 25000);
            timeline.Keyframes.Add(new Vector4(1, 0, 0, 1), 30000);
            storyboard.Add(timeline);
            storyboard.Begin();
            storyboard.Clock.Ratio = 1;

            // Generate nodes            
            Visual a = AddVisual(mesh);
            a.Transformation.Add(commonRotation);

            // Each senond nodes will have hierarchy 
            // with its previous node and have 
            // dependency on our timeline
            bool axis = true;
            Visual previous = null;
            for (int i = 0; i < 250; i++)
            {
                Visual b = AddVisual(mesh);
                b.Properties["Color"] = colorProperty;
                b.Hierarchy = previous;
                previous = b;

                ScaleTransformation scale = new ScaleTransformation(0.985, 1, 0.985);
                RotationTransformation rotation = new RotationTransformation(axis ? Vector3.XAxis : Vector3.ZAxis, new Vector3(0, 0.2, 0), 0);
                rotation.Angle = angleProperty;

                ScaleTransformation additionalScale = new ScaleTransformation(1, 1, 1);
                additionalScale.Scale = commonScale.Scale;

                b.Transformation.Add(scale);
                //b.Transformation.Add(additionalScale);
                b.Transformation.Add(rotation);

                axis = !axis;
            }


            camera.Target = aabb.Center;
            camera.Distance = (aabb.Max - aabb.Min).Length() * 0.70;
        }


        Visual AddVisual(Polygonal polygonal)
        {
            Visual visual = new Visual(polygonal);
            visual.Technique.Properties["Color"] = new Property<Color>(new Heaven.Graphics.Color(1.0, 0, 0, 1.0));
            nodeGroup.Add(visual);
            return visual;
        }

        #endregion

        #region Rendering
        
        void OnRenderRequest(object sender, EventArgs e)
        {
           // Render();
        }

        void Invalidate()
        {
            //invalidated = true;
        }

        void Render()
        {            
            /*device.Clear();
            //storyboard.Update();
            scene.Render(device);
            device.Present();*/

            //Invalidate();
        }

        #endregion
    }
}